-- CA11019.A
--
--                             Grant of Unlimited Rights
--
--     Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687,
--     F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained 
--     unlimited rights in the software and documentation contained herein.
--     Unlimited rights are defined in DFAR 252.227-7013(a)(19).  By making 
--     this public release, the Government intends to confer upon all 
--     recipients unlimited rights  equal to those held by the Government.  
--     These rights include rights to use, duplicate, release or disclose the 
--     released technical data and computer software in whole or in part, in 
--     any manner and for any purpose whatsoever, and to have or permit others 
--     to do so.
--
--                                    DISCLAIMER
--
--     ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR
--     DISCLOSED ARE AS IS.  THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED 
--     WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE
--     SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE 
--     OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A
--     PARTICULAR PURPOSE OF SAID MATERIAL.
--*
--
-- OBJECTIVE:
--      Check that body of the parent package may depend on one of its own
--      private generic children.
--
-- TEST DESCRIPTION:
--      A scenario is created that demonstrates the potential of adding a
--      generic private child during code maintenance without distubing a 
--      large subsystem.  After child is added to the subsystem, a maintainer
--      decides to take advantage of the new functionality and rewrites
--      the parent's body.
--
--      Declare a data collection abstraction in a package. Declare a private
--      generic child of this package which provides parameterized code that
--      have been written once and will be used three times to implement the
--      services of the parent package. In the parent body, instantiate the 
--      private child.  
--
--      In the main program, check that the operations in the parent, 
--      and instance of the private child package perform as expected.  
--
--
-- CHANGE HISTORY:
--      06 Dec 94   SAIC    ACVC 2.0
--      17 Nov 95   SAIC    Update and repair for ACVC 2.0.1
--
--!
  
package CA11019_0 is   
     -- parent

   type Data_Record is tagged private;
   type Data_Collection is private;
   ---
   ---
   subtype Data_1 is integer range 0 .. 100;
   procedure Add_1 (Data : Data_1; To : in out Data_Collection);  
   function Statistical_Op_1 (Data : Data_Collection) return Data_1;
   ---
   subtype Data_2 is integer range -100 .. 1000;
   procedure Add_2 (Data : Data_2; To : in out Data_Collection);
   function Statistical_Op_2 (Data : Data_Collection) return Data_2;
   ---
   subtype Data_3 is integer range -10_000 .. 10_000;
   procedure Add_3 (Data : Data_3; To : in out Data_Collection);  
   function Statistical_Op_3 (Data : Data_Collection) return Data_3;
   ---

private

   type Data_Ptr is access Data_Record'class;
   subtype Sequence_Number is positive range 1 .. 512;

   type Data_Record is tagged 
     record
        Next  : Data_Ptr := null;
        Seq   : Sequence_Number;
     end record;
   ---
   type Data_Collection is 
     record
        First : Data_Ptr := null;
        Last  : Data_Ptr := null;
     end record;
            
end CA11019_0;
 -- parent

    --=================================================================--

-- This generic package provides parameterized code that has been
-- written once and will be used three times to implement the services
-- of the parent package.

private
generic   
   type Data_Type is range <>;

package CA11019_0.CA11019_1 is    
     -- parent.child

   type Data_Elem is new Data_Record with
     record
        Value : Data_Type;
     end record;

   Next_Avail_Seq_No : Sequence_Number := 1;

   procedure Sequence (Ptr : Data_Ptr);
    -- the child must be private for this procedure to know details of
    -- the implementation of data collections

   procedure Add (Datum : Data_Type; To : in out Data_Collection);

   function  Op  (Data : Data_Collection) return Data_Type;
    -- op models a complicated operation that whose code can be
    -- used for various data types


end CA11019_0.CA11019_1;
 -- parent.child

     --=================================================================--

 
package body CA11019_0.CA11019_1 is    
          -- parent.child

   procedure Sequence (Ptr : Data_Ptr) is
   begin
      Ptr.Seq := Next_Avail_Seq_No;
      Next_Avail_Seq_No := Next_Avail_Seq_No + 1;
   end Sequence;

   ---------------------------------------------------------

   procedure Add (Datum : Data_Type; To : in out Data_Collection) is
      Ptr : Data_Ptr;
   begin
      if To.First = null then
         -- assign new record with data value to 
         -- to.next <- null;
         To.First := new Data_Elem'(Next  => null,
                                    Value => Datum,
                                    Seq   => 1);
         Sequence (To.First);
         To.Last := To.First;
      else
         -- chase to end of list
         Ptr := To.First;
         while Ptr.Next /= null loop
            Ptr := Ptr.Next;
         end loop;
         -- and add element there
         Ptr.Next := new Data_Elem'(Next  => null,
                                    Value => Datum,
                                    Seq   => 1);
         Sequence (Ptr.Next);
         To.Last := Ptr.Next;
      end if;

   end Add;

   ---------------------------------------------------------

   function  Op  (Data : Data_Collection) return Data_Type is
      -- for simplicity, just return the maximum of the data set
      Max : Data_Type := Data_Elem( Data.First.all ).Value; 
                              -- assuming non-empty collection
      Ptr : Data_Ptr  := Data.First;

   begin
      -- no error checking
      while Ptr.Next /= null loop
         if Data_Elem( Ptr.Next.all ).Value > Max then
            Max := Data_Elem( Ptr.Next.all ).Value;
         end if;
         Ptr := Ptr.Next;
      end loop;
      return Max;
   end Op;

end CA11019_0.CA11019_1;
 -- parent.child

     --=================================================================--

-- parent body depends on private generic child
with CA11019_0.CA11019_1;     -- Private generic child.

pragma Elaborate (CA11019_0.CA11019_1);
package body CA11019_0 is

   -- instantiate the generic child with data types needed by the 
   -- package interface services
   package Data_1_Ops is new CA11019_1
     (Data_Type => Data_1);
 
   package Data_2_Ops is new CA11019_1
     (Data_Type => Data_2);

   package Data_3_Ops is new CA11019_1
     (Data_Type => Data_3);

   ---------------------------------------------------------

   procedure Add_1 (Data : Data_1; To : in out Data_Collection) is
   begin
      -- maybe do other stuff here
      Data_1_Ops.Add (Data, To);
      -- and here
   end;

   ---------------------------------------------------------

   function Statistical_Op_1 (Data : Data_Collection) return Data_1 is
   begin
      -- maybe use generic operation(s) in some complicated ways
      -- (but simplified out, for the sake of testing)
      return Data_1_Ops.Op (Data);
   end;

   ---------------------------------------------------------

   procedure Add_2 (Data : Data_2; To : in out Data_Collection) is
   begin
      Data_2_Ops.Add (Data, To);
   end;

   ---------------------------------------------------------

   function Statistical_Op_2 (Data : Data_Collection) return Data_2 is
   begin
      return Data_2_Ops.Op (Data);
   end;

   ---------------------------------------------------------

   procedure Add_3 (Data : Data_3; To : in out Data_Collection) is
   begin
      Data_3_Ops.Add (Data, To);
   end;

   ---------------------------------------------------------

   function Statistical_Op_3 (Data : Data_Collection) return Data_3 is
   begin
      return Data_3_Ops.Op (Data);
   end;

end CA11019_0;


     --=================================================--

with CA11019_0,
  -- Main,    
  -- Main.Child is private
     Report;

procedure CA11019 is

   package Main renames CA11019_0;

   Col_1,
   Col_2,
   Col_3 : Main.Data_Collection;

begin

   Report.Test ("CA11019", "Check that body of a (non-generic) package " &
                "may depend on its private generic child");

   -- build a data collection

   for I in 1 .. 10 loop
      Main.Add_1 ( Main.Data_1(I), Col_1);
   end loop;

   if Main.Statistical_Op_1 (Col_1) /= 10 then 
      Report.Failed ("Wrong data_1 value returned");
   end if;

   for I in reverse 10 .. 20 loop
      Main.Add_2 ( Main.Data_2(I * 10), Col_2);
   end loop;

   if Main.Statistical_Op_2 (Col_2) /= 200 then 
      Report.Failed ("Wrong data_2 value returned");
   end if;

   for I in 0 .. 10 loop
      Main.Add_3 ( Main.Data_3(I + 5), Col_3);
   end loop;

   if Main.Statistical_Op_3 (Col_3) /= 15 then 
      Report.Failed ("Wrong data_3 value returned");
   end if;

   Report.Result;

end CA11019;
